﻿/*
   Copyright 2012 Dmitry Bratus

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Flower.Services;
using Flower.Services.Data;
using Spring.Context.Support;
using System.IO;
using Spring.Core.IO;

namespace Flower.Directory.Util
{
    public static class DirectoryUtil
    {
        public static string MakeAssemblyEntryName(AssemblyName assemblyName)
        {
            return assemblyName.Version.ToString();
        }

        public static string MakeAssemblyEntryParentPath(AssemblyName assemblyName)
        {
            return string.Concat("/Assemblies/", assemblyName.Name);
        }

        public static string AssemblyNameToPath(AssemblyName assemblyName)
        {
            return string.Concat(MakeAssemblyEntryParentPath(assemblyName), "/", MakeAssemblyEntryName(assemblyName));
        }

        public static string ResolveAssemblyName(string assemblyName)
        {
            var asmName = new AssemblyName(assemblyName);

            return 
                (asmName.Version != null) ? 
                AssemblyNameToPath(asmName) :
                string.Concat(MakeAssemblyEntryParentPath(asmName), "/Latest");
        }

        public static AssemblyName AssemblyNameFromTypeName(string typeName)
        {
            int firstIndexOfComma = typeName.IndexOf(',');

            return firstIndexOfComma > 0 ? new AssemblyName(typeName.Substring(firstIndexOfComma + 1)) : null;
        }

        public static string MakeId(int id)
        {
            return "#" + id;
        }

        public static string MakeId(long id)
        {
            return "#" + id;
        }

        public static bool IsId(string idOrPath)
        {
            return idOrPath.StartsWith("#");
        }

        public static bool IsValidDirectoryEntryName(string name)
        {
            return 
                !string.IsNullOrEmpty(name) &&
                name.All(c => char.IsLetterOrDigit(c) || c == '#' || c == '-' || c == '_' || c == '.' || c == ':');
        }

        public static string[] SplitPath(string path)
        {
            path = path.Trim('/');
            return (path.Length > 0) ? path.Split('/') : new string[0];
        }

        public static string LocalSubsetToGlobal(string pid, string subset)
        {
            return (subset.StartsWith("/") || IsId(subset)) ? subset : string.Concat("/Sets/Local/", pid, "/", subset);
        }

        public static void CutPathTailSegment(string path, out string head, out string tail)
        {
            int splitPoint = path.LastIndexOf('/');

            if (splitPoint < 0)
            {
                head = path;
                tail = string.Empty;
            }
            else if (splitPoint == 0)
            {
                head = string.Empty;
                tail = path.Substring(1);
            }
            else
            {
                head = path.Substring(0, splitPoint);
                
                if (splitPoint < path.Length - 1)
                {
                    tail = path.Substring(splitPoint + 1);
                }
                else
                {
                    tail = string.Empty;
                }
            }
        }

        public static string LastPathSegment(string path)
        {
            string head, tail;
            CutPathTailSegment(path, out head, out tail);
            return tail;
        }

        public static string AncestorPath(string path, int i)
        {
            if (i == 0)
            {
                return path;
            }

            int idxOfSlash = path.LastIndexOf('/');

            if (idxOfSlash == 0)
            {
                return "/";
            }

            return (idxOfSlash > 0) ? AncestorPath(path.Substring(0, idxOfSlash), i - 1) : null;
        }

        public static TSvc GetService<TSvc>(DirectoryEntry entry, string serviceId) where TSvc: class
        {
            Blob configuration;

            ServiceContainer serviceContainer;
            Processor processor;

            if ((serviceContainer = entry as ServiceContainer) != null)
            {
                configuration = serviceContainer.Configuration;
            }
            else if ((processor = entry as Processor) != null)
            {
                configuration = processor.Configuration;

                if (configuration == null)
                {
                    return null;
                }
            }
            else
            {
                throw new ArgumentException("The entry is neither ServiceContainer nor Processor.", "entry");
            }

            var container = new XmlApplicationContext
            (
                new XmlApplicationContextArgs
                {
                    ConfigurationResources =
                        new[] 
                        {
                            (IResource)new InputStreamResource
                            (
                                new MemoryStream(configuration.Data),
                                "Configuration"
                            )
                        }
                }
            );

            return (TSvc)container.GetObject(serviceId);
        }
    }
}
